package com.simemg.reader.utils;

import ohos.agp.components.Image;
import ohos.app.Context;
import ohos.app.dispatcher.Group;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *
 */
public class RequestUtil {

    static EventHandler mainHandler = new EventHandler(EventRunner.getMainEventRunner());

    private String url;
    private List<String> urls;
    private String method;
    private DoSomething doSomething;
    private List<DoSomething> doSomethings;
    private Image image;
    private Map<Integer, Image> images;
    private PixelMap errorImg;

    private boolean multi = false;
    private boolean returnResponse = false;
    private Context context;

    private CallBackString callBackString;
    private CallBackResponse callBackResponse;
    private CallBackObject callBackObject;
    private CallBackMapString callBackMapString;
    private CallBackMapResponse callBackMapResponse;
    private CallBackMapObject callBackMapObject;
    private ErrorBack errorBack;

    // 匿名类接口定义
    public interface CallBackString {
        void run(String s);
    }
    public interface CallBackResponse {
        void run(Response response);
    }
    public interface CallBackObject {
        void run(Object result);
    }
    public interface CallBackMapString{
        void run(Map<Integer, String> result);
    }
    public interface CallBackMapResponse{
        void run(Map<Integer, Response> result);
    }
    public interface CallBackMapObject{
        void run(Map<Integer, Object> result);
    }

    public interface DoSomething {
        Object run();
    }

    public interface ErrorBack {
        void run(Response response);
    }

    public static class Response {
        public Response() {
        }

        public InputStream inputStream;
        public InputStream errorStream;
        public int code;
        public long contentLength;
        public Exception exception;
    }

    // 链式调用定义
    public static RequestUtil Get(String url) {
        RequestUtil request = new RequestUtil();
        request.url = url;
        request.method = "GET";
        return request;
    }

    public static RequestUtil Get(List<String> urls) {
        RequestUtil request = new RequestUtil();
        request.urls = urls;
        request.multi = true;
        request.method = "GET";
        return request;
    }

    public static RequestUtil LoadImg(String url) {
        RequestUtil request = new RequestUtil();
        request.url = url;
        request.method = "LOAD_IMG";
        return request;
    }

    public static RequestUtil LoadImg(List<String> urls) {
        RequestUtil request = new RequestUtil();
        request.urls = urls;
        request.multi = true;
        request.method = "LOAD_IMG";
        return request;
    }

    public static RequestUtil Do(DoSomething doSomething) {
        RequestUtil request = new RequestUtil();
        request.doSomething = doSomething;
        request.method = "DO";
        return request;
    }

    public static RequestUtil Do(List<DoSomething> doSomethings) {
        RequestUtil request = new RequestUtil();
        request.doSomethings = doSomethings;
        request.multi = true;
        request.method = "DO";
        return request;
    }

    public RequestUtil returnResponse() {
        returnResponse = true;
        return this;
    }

    public RequestUtil setContext(Context context) {
        this.context = context;
        return this;
    }

    public RequestUtil setImage(Image image) {
        this.image = image;
        return this;
    }

    public RequestUtil setImage(Map<Integer, Image> images) {
        this.images = images;
        return this;
    }

    public RequestUtil setImage(Image image, PixelMap errorImg) {
        this.image = image;
        this.errorImg = errorImg;
        return this;
    }


    public RequestUtil setImage(Map<Integer, Image> images, PixelMap errorImg) {
        this.images = images;
        this.errorImg = errorImg;
        return this;
    }


    public RequestUtil onSuccess(CallBackString callBackString) {
        this.callBackString = callBackString;
        return this;
    }

    public RequestUtil onSuccess(CallBackResponse callBackResponse) {
        this.callBackResponse = callBackResponse;
        return this;
    }

    public RequestUtil onSuccess(CallBackObject callBackObject) {
        this.callBackObject = callBackObject;
        return this;
    }

    public RequestUtil onSuccess(CallBackMapString callBackMapString) {
        this.callBackMapString = callBackMapString;
        return this;
    }

    public RequestUtil onSuccess(CallBackMapResponse callBackMapResponse) {
        this.callBackMapResponse = callBackMapResponse;
        return this;
    }

    public RequestUtil onSuccess(CallBackMapObject callBackMapObject) {
        this.callBackMapObject = callBackMapObject;
        return this;
    }

    public RequestUtil onFail(ErrorBack errorBack) {
        this.errorBack = errorBack;
        return this;
    }

    // 执行程序
    public void execute() {
        if (multi)
            multiExecute();
        else
            singleExecute();
    }

    // 单线程执行
    private void singleExecute() {
        new Thread(()->{
            switch (method) {
                case "GET":
                    if (returnResponse) singleGetReturnResponse(); else singleGetReturnString();
                    break;
                case "DO":
                    singleDoSomeThing();
                    break;
                case "LOAD_IMG":
                    singleLoadImg();
                    break;
            }
        }).start();
    }

    private void multiExecute() {
        new Thread(()->{
            switch (method) {
                case "GET":
                    if (returnResponse) multiGetReturnResponse(); else multiGetReturnString();
                    break;
                case "DO":
                    multiDoSomeThing();
                    break;
            }
        }).start();
    }

    private void singleGetReturnString() {
        try {
            URL url = new URL(this.url);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();

            int resCode = conn.getResponseCode();
            if (resCode == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = conn.getInputStream();
                String result = new BufferedReader(new InputStreamReader(inputStream))
                        .lines().collect(Collectors.joining(System.lineSeparator()));
                mainHandler.postTask(() -> {
                    if(callBackString !=null) callBackString.run(result);
                });
            }
            else {
                Response response = new Response();
                response.code = conn.getResponseCode();
                response.contentLength = (long)conn.getContentLength();
                response.inputStream = conn.getInputStream();
                response.errorStream = conn.getErrorStream();
                mainHandler.postTask(() -> {
                    if(errorBack!=null) errorBack.run(response);
                });
            }
        }
        catch (IOException e) {
            Response response = new Response();
            response.exception = e;
            mainHandler.postTask(() -> {
                if(errorBack!=null) errorBack.run(response);
            });
        }
    }

    private void singleGetReturnResponse() {
        try {
            URL url = new URL(this.url);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            Response response = new Response();
            response.code = conn.getResponseCode();
            response.contentLength = (long)conn.getContentLength();
            response.inputStream = conn.getInputStream();
            response.errorStream = conn.getErrorStream();
            mainHandler.postTask(() -> {
                if(callBackResponse !=null) callBackResponse.run(response);
            });
        }
        catch (IOException e) {
            Response response = new Response();
            response.exception = e;
            mainHandler.postTask(() -> {
                if(errorBack!=null) errorBack.run(response);
            });
        }
    }

    private void singleDoSomeThing() {
        Object result = doSomething.run();
        mainHandler.postTask(() -> {if(callBackObject!=null) callBackObject.run(result);});
    }

    private void multiGetReturnString() {
        int size = urls.size();
        Map<Integer, String> result = new HashMap<>();
        Map<Integer, Response> response = new HashMap<>();

        TaskDispatcher dispatcher  = context.getGlobalTaskDispatcher(TaskPriority.DEFAULT);
        Group group = dispatcher.createDispatchGroup();
        for (int i = 0; i < size; i++) {
            String urlStr = urls.get(i);
            int finalI = i;
            dispatcher.asyncGroupDispatch(group, () -> {
                try {
                    URL url = new URL(urlStr);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.connect();

                    int resCode = conn.getResponseCode();
                    if (resCode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = conn.getInputStream();
                        String res = new BufferedReader(new InputStreamReader(inputStream))
                                .lines().collect(Collectors.joining(System.lineSeparator()));
                        result.put(finalI, res);
                    }
                    else {
                        Response rsp = new Response();
                        rsp.code = conn.getResponseCode();
                        rsp.contentLength = (long)conn.getContentLength();
                        rsp.inputStream = conn.getInputStream();
                        rsp.errorStream = conn.getErrorStream();
                        response.put(finalI, rsp);
                    }
                }
                catch (IOException e) {
                    Response rsp = new Response();
                    rsp.exception = e;
                    response.put(finalI, rsp);
                }
            });
        }
        // 所有任务结束执行
        dispatcher.groupDispatchNotify(group,() -> {
            if(result.size()>0)mainHandler.postTask(() -> {if(callBackMapString!=null)callBackMapString.run(result);});
            if(response.size()>0)mainHandler.postTask(() -> {if(callBackMapResponse!=null)callBackMapResponse.run(response);});
        });
    }

    private void multiGetReturnResponse() {
        int size = urls.size();
        Map<Integer, Response> response = new HashMap<>();

        TaskDispatcher dispatcher  = context.getGlobalTaskDispatcher(TaskPriority.DEFAULT);
        Group group = dispatcher.createDispatchGroup();
        for (int i = 0; i < size; i++) {
            String urlStr = urls.get(i);
            int finalI = i;
            dispatcher.asyncGroupDispatch(group, () -> {
                try {
                    URL url = new URL(urlStr);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.connect();
                    Response rsp = new Response();
                    rsp.code = conn.getResponseCode();
                    rsp.contentLength = (long)conn.getContentLength();
                    rsp.inputStream = conn.getInputStream();
                    rsp.errorStream = conn.getErrorStream();
                    response.put(finalI, rsp);
                }
                catch (IOException e) {
                    Response rsp = new Response();
                    rsp.exception = e;
                    response.put(finalI, rsp);
                }
            });
        }
        // 所有任务结束执行
        dispatcher.groupDispatchNotify(group,() -> {
            if(response.size()>0)mainHandler.postTask(() -> {if(callBackMapResponse!=null)callBackMapResponse.run(response);});
        });
    }

    private void multiDoSomeThing() {
        int size = doSomethings.size();
        if (size == 0) return;
        Map<Integer, Object> result = new HashMap<>();

        TaskDispatcher dispatcher = context.getGlobalTaskDispatcher(TaskPriority.DEFAULT);
        Group group = dispatcher.createDispatchGroup();
        for (int i = 0; i < size; i++) {
            int finalI = i;
            dispatcher.asyncGroupDispatch(group, () -> {
                DoSomething task = doSomethings.get(finalI);
                Object res = task.run();
                result.put(finalI, res);
            });
        }
        // 所有任务结束执行
        dispatcher.groupDispatchNotify(group,() -> {
            if(result.size()>0)mainHandler.postTask(()->{if(callBackMapObject!=null)callBackMapObject.run(result);});
        });
    }

    private void singleLoadImg(){
        if (image == null) return;
        try {
            URL url = new URL(this.url);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            InputStream inputStream = conn.getInputStream();
            ImageSource imageSource = ImageSource.create(inputStream, null);
            if (imageSource == null) {
                if (errorImg != null) {
                    context.getUITaskDispatcher().asyncDispatch(() -> {
                        image.setPixelMap(errorImg);
                        errorImg.release();
                    });
                }
            }
            else {
                PixelMap pixelMap = imageSource.createPixelmap(null);
                context.getUITaskDispatcher().asyncDispatch(() -> {
                    image.setPixelMap(pixelMap);
                    pixelMap.release();
                });
            }
        }
        catch (IOException e) {
            if (errorImg != null) {
                context.getUITaskDispatcher().asyncDispatch(() -> {
                    image.setPixelMap(errorImg);
                    errorImg.release();
                });
            }
        }
    }




}